"""
Plugins support module, contains base class for plugin and plugins maintenance code.
"""

import sys
import os.path
import re

from . import log
from . import exceptions

class Plugin(object):
    """
    Base class for plugin.
    """
    def __init__(self):
        self.capabilities = []
        
    def supported_file_types(self):
        """
        Returns supported file types.
        
        @return: tuple with file name extensions, for example, ("fb2", "fb2.zip")
        """
        raise NotImplementedError

#class Document(object):
##    """
#    Base class for digital representation of the documents metadata.
#    """
    
loaded = []
plugins = dict()
file_types_mapping = dict()

def initialize(plugin_paths):
    """
    Initialize plugins system
    
    @param plugin_paths: list of directories with plugins
    """
    for path in plugin_paths:
        load_file_plugins(path)
        
def load_file_plugins(plugins_path):
    global loaded, plugins, file_types_mapping
    
    plugins_path = os.path.join(plugins_path, "file-plugins")
    # find all *.py files and directories
    if not os.path.isdir(plugins_path):
        return
    
    oldpath = sys.path
    sys.path.insert(0, plugins_path)
    
    file_types_mapping = dict()

    for file in os.listdir(plugins_path):
        fullpath = os.path.join(plugins_path, file)
        if file.endswith(".py") or os.path.isdir(fullpath):
            
            plugin_id = re.sub('\.pyc?$', '', file)
            try:
                # FIXME: handle situation with already loaded plugins
                log.debug("Trying to load plugin %s" % plugin_id)
                plugin = __import__(plugin_id)
            except ImportError, e:
                log.error("Unable to import plugin module: %s" % e )
                continue
            except ValueError, e:
                log.error("Unable to import plugin module `%s': %s" % (file, e) )
                continue
                
            
            if not hasattr(plugin, "PLUGIN_NAME"):
                log.error("Invalid plugin `%s', attribute PLUGIN_NAME is required" % fullpath)
                continue
            
            if not hasattr(plugin, "PLUGIN_SUPPORTED_FILE_TYPES") or not isinstance(plugin.PLUGIN_SUPPORTED_FILE_TYPES, tuple):
                log.error("Invalid plugin `%s', attribute PLUGIN_SUPPORTED_FILE_TYPES is requried" % fullpath)
                continue
            
            if not hasattr(plugin, "extract_metadata") or not callable(plugin.extract_metadata):
                log.error("Invalid plugin `%s', function `extract_metadata' not found" % fullpath)
                continue
            
            for k in plugin.PLUGIN_SUPPORTED_FILE_TYPES:
                file_types_mapping[k] = plugin_id
            
            loaded.append(plugin.PLUGIN_NAME)
            plugins[plugin_id] = plugin
            log.debug("Loaded plugin: %s" % plugin.PLUGIN_NAME)
        
    sys.path = oldpath
    
def get_plugin(plugin_id):
    if not plugin_id in plugins:
        raise exceptions.PluginNotFoundError("Unknown plugin with id `%s'" % plugin_id)
    
    return plugins[plugin_id]

def construct_attr(name, value, params=None):
    m = {'attr_name': name, 'attr_value': value, 'attr_params': list()}
    
    if isinstance(params, list):
        m['attr_params'] = params
        
    return m

def find_plugin_for_file(filename):
    filename = str(filename)
    
    for k in file_types_mapping:
        if filename.lower().endswith("."+k):
            return file_types_mapping[k]
        
    return None

def extract_extension_from_filename(filename):
    """
    Extract file extension.
    """
    filename = str(filename)
    
    for k in file_types_mapping:
        if filename.lower().endswith("."+k):
            return k
        
    return None
    
